//////////////////////////////////////////////////////////////////////////////////
// Company:  
// Engineer:  
// Target Devices:  
// Tool versions:
//
// Create Date:    2011-08-18 15:28
// Project Name:    
// Description: 1. model OV7221 timing,see OV7221.pdf,page 9, Figure 6.
//
// Dependencies:
//
// Revision: 1.0
// Revision 0.01 - File Created
//
//
//////////////////////////////////////////////////////////////////////////////////
`timescale 1ns/1ns
module ov7221
#(
    parameter P_CLK   = 10_000_000, //10Mhz,25fps
    parameter H_SIZE  = 640,
    parameter V_SIZE  = 480
)
(
    output reg[7:0] data,
    output reg      v_sync,
    output reg      h_sync,
    output reg      href,
    output reg      pclk
);

/********************************************************\
Parameter
\********************************************************/
localparam U_DLY = 1;
localparam BUF_SIZE = H_SIZE*V_SIZE;
localparam tPCLK = 1_000_000_000/P_CLK;  

// OV7221 timing parameter,unit tPCLK
localparam tROW_H   = H_SIZE*tPCLK;
localparam tROW_L   = 144*tPCLK;
localparam tROW     = tROW_L + tROW_H;
localparam tVSYNC_H = 4*tROW;
localparam tVSYNC = 510*(tROW_H+tROW_L);


/********************************************************\
Signals
\********************************************************/

reg [7:0]   mem[0:BUF_SIZE-1];

reg [15:0]  v_cnt;
reg [15:0]  h_cnt;

/********************************************************\
main code
\********************************************************/

initial
begin
    data    = 8'h0;
    v_sync  = 1'b0;
    h_sync  = 1'b0;
    pclk    = 1'b0;
    href    = 1'b0;
    v_cnt   = 'h0;
    h_cnt   = 'h0;
end 

// Generate pclk
always
    #(tPCLK/2) pclk = ~pclk;

// generate VSYNC
initial
begin
    #tROW;
    while(1)
    begin
        v_sync = 1'b1;
        #(4*tROW);
        v_sync = 1'b0;
        #(506*tROW);
    end
end

// generate HREF
initial
begin:HREF_GEN
    integer i;
    while(1)
    begin
       @(negedge v_sync);
       #(20*tROW);
       for(i = 0; i < V_SIZE; i = i + 1)
       begin
            href = 1'b1;
            #(tROW_H);
            href = 1'b0;
            #(tROW_L);
       end
    end
end

// generate h_sync
initial
begin:H_GEN
    integer i;
    while(1)
    begin
       @(negedge v_sync);
       h_sync = 1'b0;
       #(20*tROW-76*tPCLK);
       for(i = 0; i < V_SIZE; i = i + 1)
       begin
            h_sync = 1'b1;
            @(negedge href);
            #(4*tPCLK);
            h_sync = 1'b0;
            #(64*tPCLK);
       end
    end
end

always@(posedge pclk,posedge v_sync)
begin
    if(v_sync==1'b1)
    begin
        h_cnt   <= 0;
    end
    else if(href)
    begin
        h_cnt   <= #1 h_cnt + 1'b1;
    end
    else
    begin
        h_cnt   <= #1 0;
    end
end

always@(negedge h_sync,posedge v_sync)
begin
    if(v_sync==1'b1)
    begin
        v_cnt   <= 'h0;
    end
    else
    begin
        v_cnt   <= #1 v_cnt + 1'b1;
    end
end

/*******************************************************\
    Read image from file and output in ov7221 timing
Useage:
    OV7221_OUT_TASK(file_name);
\*******************************************************/    
task OV7221_OUT_TASK;
    input reg[128*8:0] file_name;
    begin
        $readmemh(file_name,mem);
        while(1)
        begin
            @(negedge pclk);
            data <= #1 mem[v_cnt*H_SIZE + h_cnt];
        end
    end
endtask

endmodule
